﻿using Cuofrisp.Core.ParallelCore.Interfaces;
using Cuofrisp.Core.ParallelCore.Tools;
using MathNet.Symbolics;

namespace Cuofrisp.Core.ParallelCore
{
    public sealed partial class ParallelCuofrispCalculator : ICuofrispCalculator
    {
        private readonly IExpressionSimplifier simplifier;
        private readonly IMetricInverseProvider inverseProvider;
        private readonly ParallelOptions parallelOptions;
        public ParallelCuofrispCalculator(
            IExpressionSimplifier? simplifier = null,
            IMetricInverseProvider? inverseProvider = null,
            int? maxDegreeOfParallelism = null)
        {
            this.parallelOptions = new() {
                MaxDegreeOfParallelism = maxDegreeOfParallelism ?? Environment.ProcessorCount
            };

            this.simplifier = simplifier ?? new ExpressionSimplifier();
            this.inverseProvider = inverseProvider ?? new MetricInverseProvider() {
                ParallelOptions = this.parallelOptions
            };
        }

        public CuofrispResult Calculate(SymbolicExpression[] variables, SymbolicExpression[,] metric)
        {
            var variableCount = variables.Length;
            if (variableCount != metric.GetLength(0) || variableCount != metric.GetLength(1))
            {
                throw new ArgumentException(
                    $"{nameof(metric)} 维度 0 的长度与 {nameof(variables)} 的长度不一致。");
            }
            if (variableCount != metric.GetLength(1))
            {
                throw new ArgumentException(
                    $"{nameof(metric)} 维度 1 的长度与 {nameof(variables)} 的长度不一致。");
            }

            var result = new CuofrispResult(variableCount);

            this.SetInput(result, variables, metric, out var containsNull);
            if (containsNull)
            {
                throw new ArgumentException(
                    $"{nameof(variables)} 或 {nameof(metric)} 中存在值为 null 的项。");
            }

            this.SetMetricInverse(result, out var isNotFullRank);
            if (isNotFullRank)
            {
                throw new ArgumentException(
                    $"{nameof(metric)} 不满秩。", nameof(metric));
            }

            this.SetMetricDerivative(result);
            this.SetChristoffelAndDerivative(result);
            this.SetCurvature(result);

            return result;
        }
    }
}